home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / vg-2.03 / video / video.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-03  |  11.7 KB  |  661 lines

  1. /*
  2.  * Copyright (C) 1990-1992 Michael Davidson.
  3.  * All rights reserved.
  4.  *
  5.  * Permission to use, copy, modify, and distribute this software
  6.  * and its documentation for any purpose and without fee is hereby
  7.  * granted, provided that the above copyright notice appear in all
  8.  * copies and that both that copyright notice and this permission
  9.  * notice appear in supporting documentation.
  10.  *
  11.  * This software is provided "as is" without express or implied warranty.
  12.  */
  13.  
  14. #include    <stdlib.h>
  15. #include    <stdio.h>
  16. #include    <string.h>
  17. #include    <memory.h>
  18. #include    <setjmp.h>
  19. #include    <errno.h>
  20. #include    <signal.h>
  21. #include    <unistd.h>
  22. #include    <sys/types.h>
  23. #if defined(SVR4)
  24. #include    <sys/kd.h>
  25. #include    <sys/vt.h>
  26. #define    VT_TRUE    1
  27. #else
  28. #include    <sys/vtkd.h>
  29. #endif
  30.  
  31. #include    "video.h"
  32. #include    "vbios.h"
  33. #include    "vdev.h"
  34.  
  35. /*
  36.  * color palette
  37.  */
  38. unsigned    Black;
  39. unsigned    White;
  40.  
  41. /*
  42.  * 8 x 14 Font
  43.  */
  44. font_t        *Font8x14;
  45. font_t        *DefaultFont;
  46.  
  47. /*
  48.  * Pixel lookup table for 8 bit displays
  49.  */
  50. unsigned char    VPixelLookup[32 * 1024];
  51.  
  52. /*
  53.  * Text mode screen
  54.  */
  55. static unsigned char    *TextScreen    = NULL;
  56. static int        TextMode    = -1;
  57. static vmode_t        *TextModeInfo    = NULL;
  58. static void        textRedraw();
  59.  
  60. /*
  61.  * screen switch handling
  62.  */
  63. STATIC int    vidCheckDisplayed();
  64.  
  65. STATIC int    video_flags        = 0;
  66.  
  67. #define        VIDEO_DISPLAYED        0x01
  68. #define        VIDEO_SWITCH_AWAY    0x02
  69. #define        VIDEO_SWITCH_BACK    0x04
  70.  
  71.  
  72. STATIC int    video_fd        = 0;
  73.  
  74. STATIC vdev_t    video_dev;
  75. STATIC int    VideoMode        = -1;
  76. STATIC vmode_t    *VideoModeInfo        = NULL;
  77.  
  78. STATIC void    switch_away(int);
  79. STATIC void    switch_back(int);
  80. STATIC void    vidRedraw();
  81.  
  82. STATIC int    vidNull();
  83.  
  84. STATIC int    (*graphicsRedraw)()    = vidNull;
  85.  
  86. STATIC void    vidDevInit(char    *name, vdev_t *vdevp);
  87.  
  88. /*
  89.  * display initialisation
  90.  */
  91. void
  92. vidInit(
  93.     char    *display
  94.     )
  95. {
  96.     struct vt_mode    smode;
  97.     static font_t    vga_8x14;
  98.  
  99.     video_fd    = 0;
  100.  
  101.     /*
  102.      * must be root or setuid root to run this
  103.      */
  104.     if (geteuid() != 0)
  105.     fatal(0, "must be root or setuid root");
  106.  
  107.     /*
  108.      * set up signal handlers for screen switching
  109.      */
  110.     smode.mode     = VT_PROCESS;
  111.     smode.waitv  = 0;
  112.     smode.relsig = SIGUSR1;
  113.     smode.acqsig = SIGUSR2;
  114.     smode.frsig  = SIGINT;
  115.  
  116.     signal(SIGUSR1, switch_away);
  117.     signal(SIGUSR2, switch_back);
  118.     if (ioctl(video_fd, VT_SETMODE, &smode) != 0)
  119.     fatal(errno, "can't set screen-switch handlers");
  120.  
  121.     /*
  122.      * check that this process is running on the currently
  123.      * displayed screen and, if necessary, wait until this
  124.      * screen is switched to
  125.      */
  126.     while (ioctl(video_fd, VT_RELDISP, VT_ACKACQ) < 0)
  127.     pause();
  128.  
  129.     if (ioctl(video_fd, KDSETMODE, KD_GRAPHICS) != 0)
  130.     fatal(errno, "can't set display to graphics mode");
  131.  
  132.     if (VBiosInit() != 0)
  133.     fatal(errno, "can't initialise video BIOS");
  134.  
  135.     vidDevInit(display, &video_dev);
  136.  
  137.     if ((vga_8x14.f_data = (unsigned char *)VBiosGetFontInfo(2)) == NULL)
  138.     fatal(0, "can't access VGA 8x14 font");
  139.     vga_8x14.f_width    = 8;
  140.     vga_8x14.f_height    = 14;
  141.  
  142.     Font8x14    = &vga_8x14;
  143.     DefaultFont    = Font8x14;
  144.  
  145.     video_flags    = VIDEO_DISPLAYED;
  146.  
  147. }
  148.  
  149. STATIC void
  150. vidDevInit(
  151.     char    *name,
  152.     vdev_t    *vdevp
  153.     )
  154. {
  155.     struct    vdevinit    *d;
  156.  
  157.     if (name != NULL)
  158.     {
  159.     for (d = vdevsw; d->name != NULL; d++)
  160.     {
  161.         if (strcmp(name, d->name) == 0)
  162.         {
  163.             if ((*d->init)(name, vdevp) == 0)
  164.             return;
  165.         fatal(0, "initialisation of display type '%s' failed", name);
  166.         }
  167.     }
  168.     fatal(0, "display type '%s' not supported", name);
  169.     }
  170.  
  171.     /*
  172.      * try to auto-detect
  173.      */
  174.     for (d = vdevsw; d->name != NULL; d++)
  175.     {
  176.     if ((*d->probe)() > 0)
  177.     {
  178.         if ((*d->init)(name, vdevp) == 0)
  179.         return;
  180.         fatal(0, "initialisation of display type '%s' failed", name);
  181.     }
  182.     }
  183.  
  184.     fatal(0, "auto-detection failed: cannot determine display type");
  185. }
  186.  
  187. /*
  188.  * display reset
  189.  */
  190. void
  191. vidReset()
  192. {
  193.     struct vt_mode smode;
  194.  
  195.     if (vidCheckDisplayed())
  196.     (*video_dev.v_reset)();
  197.  
  198.     if (ioctl(video_fd, KDSETMODE, KD_TEXT) != 0)
  199.     fatal(errno, "can't set display to text mode");
  200.  
  201.     write(video_fd, "\f", 1);
  202.  
  203.     smode.mode     = VT_AUTO;
  204.     smode.waitv  = 0;
  205.     smode.relsig = 0;
  206.     smode.acqsig = 0;
  207.     smode.frsig  = 0;
  208.     ioctl(video_fd, VT_SETMODE, &smode);
  209.     signal(SIGUSR1, SIG_IGN);
  210.     signal(SIGUSR2, SIG_IGN);
  211. }
  212.  
  213. /*
  214.  * vidGetModes()    - returns pointer to table of supported modes
  215.  */
  216. vmode_t    *
  217. vidGetModes()
  218. {
  219.     return video_dev.v_modes;
  220. }
  221.  
  222. /*
  223.  * vidModeInfo()    - returns pointer to information for the mode specified
  224.  */
  225. vmode_t    *
  226. vidModeInfo(
  227.     int        i
  228.     )
  229. {
  230.     return &((vmode_t *)video_dev.v_modes)[i];
  231. }
  232.  
  233. /*
  234.  * vidGetName()    - returns display name
  235.  */
  236. char *
  237. vidGetName()
  238. {
  239.     return video_dev.v_name;
  240. }
  241.  
  242. /*
  243.  * vidSetMode()    - sets display mode
  244.  */
  245. int
  246. vidSetMode(
  247.     int        i
  248.     )
  249. {
  250.     if (vidCheckDisplayed())
  251.     if ((*video_dev.v_setmode)(i) != 0)
  252.         return -1;
  253.  
  254.     VideoMode        = i;
  255.     VideoModeInfo    = vidModeInfo(i);
  256.  
  257.     if (VideoModeInfo->flags & V_TEXT_MODE)
  258.     {
  259.     if (i == TextMode)
  260.     {
  261.         textRedraw();
  262.     }
  263.     else
  264.     {
  265.         vmode_t    *m = VideoModeInfo;
  266.  
  267.         if (TextScreen)
  268.         free(TextScreen);
  269.  
  270.         if ((TextScreen = calloc(m->width * m->height, 2)) == NULL)
  271.         fatal(errno, "can't allocate memory for %d x %d text screen",
  272.             m->width, m->height);
  273.  
  274.         TextMode        = i;
  275.         TextModeInfo    = m;
  276.         }
  277.     }
  278.  
  279.     Black    = 0;
  280.     White    = 1;
  281.  
  282.     return 0;
  283. }
  284.  
  285. /*
  286.  * vidGetMode()    - returns current display mode
  287.  */
  288. vidGetMode()
  289. {
  290.     return VideoMode;
  291. }
  292.  
  293. /*
  294.  * vidClear()
  295.  */
  296. void
  297. vidClear(
  298.     unsigned    color
  299.     )
  300. {
  301.     if (vidCheckDisplayed())
  302.     (*video_dev.v_clear)(color);
  303.  
  304.     if (VideoMode == TextMode)
  305.     memset(TextScreen, color | (color << 4),
  306.         TextModeInfo->width * TextModeInfo->height * 2);
  307. }
  308.  
  309. /*
  310.  * vidSetPalette()    - sets video palette
  311.  */
  312. void
  313. vidSetPalette(
  314.     color_t    *colormap,
  315.     int        ncolors
  316.     )
  317. {
  318.     int        i;
  319.     unsigned    l, lmax, lmin;
  320.  
  321.     if (vidCheckDisplayed())
  322.     (*video_dev.v_setpalette)(colormap, ncolors);
  323.  
  324.     lmax    = 0;
  325.     lmin    = 255;
  326.  
  327.  
  328.     for (i = 0; i < ncolors; i++, colormap++)
  329.     {
  330.     l =  colormap->red * 77;
  331.     l += colormap->green * 150;
  332.     l += colormap->blue * 29;
  333.     l /= 256;
  334.  
  335.     if (l > lmax)
  336.     {
  337.         lmax    = l;
  338.         White    = i;
  339.     }
  340.  
  341.     if (l < lmin)
  342.     {
  343.         lmin    = l;
  344.         Black    = i;
  345.     }
  346.     }
  347. }
  348.  
  349. /*
  350.  * vidPutPixels8()    - writes 8 bit pixels to the display
  351.  *            - note that PutPixels() can be used to write
  352.  *              at most one scanline at a time and that it
  353.  *              clips to the actual size of the display in
  354.  *              the current mode
  355.  */
  356. vidPutPixels8(
  357.     int        x,
  358.     int        y,
  359.     pixel8_t    *pixbuf,
  360.     int        npixels
  361.     )
  362. {
  363.     if (y >= VideoModeInfo->height)
  364.     return 0;
  365.  
  366.     if (x >= VideoModeInfo->width)
  367.     return 0;
  368.  
  369.     if (x+npixels > VideoModeInfo->width)
  370.     npixels = VideoModeInfo->width - x;
  371.  
  372.     if (vidCheckDisplayed())
  373.     (*video_dev.v_putpixels8)(x, y, pixbuf, npixels);
  374.  
  375.     return npixels;
  376. }
  377.  
  378. /*
  379.  * vidPutPixels24()    - writes 24 bit pixels to the display
  380.  *            - note that PutPixels() can be used to write
  381.  *              at most one scanline at a time and that it
  382.  *              clips to the actual size of the display in
  383.  *              the current mode
  384.  */
  385. vidPutPixels24(
  386.     int        x,
  387.     int        y,
  388.     pixel24_t    *pixbuf,
  389.     int        npixels
  390.     )
  391. {
  392.     if (y >= VideoModeInfo->height)
  393.     return 0;
  394.  
  395.     if (x >= VideoModeInfo->width)
  396.     return 0;
  397.  
  398.     if (x+npixels > VideoModeInfo->width)
  399.     npixels = VideoModeInfo->width - x;
  400.  
  401.     if (vidCheckDisplayed())
  402.     (*video_dev.v_putpixels24)(x, y, pixbuf, npixels);
  403.  
  404.     return npixels;
  405. }
  406.  
  407. /*
  408.  * vidPutText()        - writes text to the display when in text mode
  409.  */
  410. void
  411. vidPutText(
  412.     int        x,
  413.     int        y,
  414.     char    *buf,
  415.     int        nbytes,
  416.     int        fg,
  417.     int        bg
  418.     )
  419. {
  420.     unsigned char    *p;
  421.     unsigned char    attr;
  422.     int            n;
  423.  
  424.     if (VideoMode != TextMode)
  425.     return;
  426.  
  427.     p        = TextScreen + ((y * TextModeInfo->width) + x) * 2;
  428.     attr    = (fg & 0x0f) | ((bg & 0x0f) << 4);
  429.     n        = nbytes;
  430.  
  431.     while (--n >= 0)
  432.     {
  433.     *p++ = *buf++;
  434.     *p++ = attr;
  435.     }
  436.  
  437.     p        = TextScreen + ((y * TextModeInfo->width) + x) * 2;
  438.     if (vidCheckDisplayed())
  439.     (*video_dev.v_puttext)(x, y, p, nbytes * 2);
  440. }
  441.  
  442. /*
  443.  * vidDrawText()        - draws text on the display when in graphics mode
  444.  */
  445. void
  446. vidDrawText(
  447.     int        x,
  448.     int        y,
  449.     char    *text,
  450.     int        len,
  451.     font_t    *font
  452.     )
  453. {
  454.     unsigned char    c;
  455.     int            i, j, k, l;
  456.     unsigned char    *f, *p, pix;
  457.     void        *pixels;
  458.     int            n;
  459.     int            w;
  460.     int            fg;
  461.     int            bg;
  462.     int            bpp;
  463.     extern void        *alloca(int);
  464.  
  465.     if (! (VideoModeInfo->flags & V_GRAPHICS_MODE))
  466.     return;
  467.  
  468.     if (VideoModeInfo->depth <= 8)
  469.     {
  470.     bpp = 1;
  471.     fg = White;
  472.     bg = Black;
  473.     }
  474.     else
  475.     {
  476.     bpp = 3;
  477.     fg = 0xff;
  478.     bg = 0x00;
  479.     }
  480.  
  481.     n        = len * font->f_width;
  482.     pixels    = alloca(n * bpp);
  483.     w        = (font->f_width + 7) / 8;
  484.  
  485.     for (i = 0; i < font->f_height; i++)
  486.     {
  487.     p = pixels;
  488.     for (j = 0; j < len; j++)
  489.     {
  490.         c    = text[j];
  491.  
  492.         f = font->f_data + w * (c * font->f_height + i);
  493.         for (k = 0; k < font->f_width; k++)
  494.         {
  495.         if ((k & 7) == 0)
  496.             c = *f++;
  497.         pix = (c & 0x80) ? fg : bg;
  498.         for (l = 0; l < bpp; l++)
  499.             *p++ = pix;
  500.         c <<= 1;
  501.         }
  502.     }
  503.     if (bpp == 1)
  504.         vidPutPixels8(x, y + i, pixels, n);
  505.     else
  506.         vidPutPixels24(x, y + i, pixels, n);
  507.     }
  508. }
  509.  
  510. void
  511. vidSetGraphicsRedraw(
  512.     int        (*redraw)()
  513.     )
  514. {
  515.     graphicsRedraw = redraw;
  516. }
  517.  
  518. STATIC int
  519. vidNull()
  520. {
  521.     return 0;
  522. }
  523.  
  524. void
  525. textRedraw()
  526. {
  527.     int        i;
  528.  
  529.     if (VideoMode != TextMode)
  530.     return;
  531.  
  532.     for (i = 0; i < TextModeInfo->height; i++)
  533.     {
  534.     if (vidCheckDisplayed())
  535.         (*video_dev.v_puttext)(0, i, TextScreen + TextModeInfo->width * i * 2,
  536.         TextModeInfo->width * 2);
  537.     }
  538. }
  539.  
  540. STATIC int
  541. vidCheckDisplayed()
  542. {
  543.     (void) vidCheckScreenSwitch(0);
  544.  
  545.     return (video_flags & VIDEO_DISPLAYED);
  546. }
  547.  
  548. /*
  549.  * vidCheckScreenSwitch(block)    - handle pending screen switch request
  550.  *                - if "block" is true then requests to
  551.  *                  switch away will block here until a
  552.  *                  switch back occurs
  553.  *                - returns 0 if there is no screen switch
  554.  *                - returns 1 if a screen switch occurred
  555.  */
  556. int
  557. vidCheckScreenSwitch(
  558.     int        block
  559.     )
  560. {
  561.     if (! (video_flags & (VIDEO_SWITCH_AWAY | VIDEO_SWITCH_BACK)) )
  562.     return 0;
  563.  
  564.     if (video_flags & VIDEO_SWITCH_AWAY)
  565.     {
  566.     if (video_flags & VIDEO_DISPLAYED)
  567.         (*video_dev.v_reset)();
  568.  
  569.     if (ioctl(video_fd, KDSETMODE, KD_TEXT) != 0)
  570.         fatal(errno, "can't set display to text mode");
  571.  
  572.     video_flags &= ~(VIDEO_SWITCH_AWAY | VIDEO_DISPLAYED);
  573.  
  574.     ioctl(video_fd, VT_RELDISP, VT_TRUE);
  575.  
  576.     /*
  577.      * if we do not want to block return immediately and
  578.      * indicate that a screen-switch has taken place
  579.      */
  580.     if (block == 0)
  581.         return 1;
  582.  
  583.     while (! (video_flags & VIDEO_SWITCH_BACK))
  584.         pause();
  585.     }
  586.  
  587.     if (video_flags & VIDEO_SWITCH_BACK)
  588.     {
  589.     video_flags &= ~VIDEO_SWITCH_BACK;
  590.  
  591.     ioctl(video_fd, VT_RELDISP, VT_ACKACQ);
  592.  
  593.     video_flags |= VIDEO_DISPLAYED;
  594.  
  595.     if (ioctl(video_fd, KDSETMODE, KD_GRAPHICS) != 0)
  596.         fatal(errno, "can't set display to graphics mode");
  597.  
  598.     (*video_dev.v_setmode)(VideoMode);
  599.  
  600.     vidRedraw();
  601.     }
  602.  
  603.     return 1;
  604. }
  605.  
  606. /*
  607.  * vidRedraw()    - called from screen switch handling to redraw the screen
  608.  *          Since another screen switch can occur while the redraw
  609.  *          is in progress vidRedraw() traps any recursive calls to
  610.  *          itself and unwinds the stack to the top level. This
  611.  *          means that functions called by vidRedraw() must not allocate
  612.  *          any resources.
  613.  */
  614. STATIC void
  615. vidRedraw()
  616. {
  617.     static int        redraw_in_progress    = 0;
  618.     static jmp_buf    redraw_unwind;
  619.  
  620.     if (redraw_in_progress)
  621.     longjmp(redraw_unwind, 1);
  622.  
  623.     setjmp(redraw_unwind);
  624.     redraw_in_progress = 1;
  625.  
  626. /*
  627.  * NOTE: actually do the redraw here
  628.  *     the mode has already been set - need to reset the palette
  629.  *     and redraw the screen
  630.  */
  631.     if (VideoModeInfo->flags & V_TEXT_MODE)
  632.     textRedraw();
  633.     else
  634.     (void)graphicsRedraw();
  635.  
  636.     redraw_in_progress = 0;
  637. }
  638.  
  639. /*
  640.  * screen switch signal handlers
  641.  */
  642.  
  643. STATIC void
  644. switch_away(
  645.     int        sig
  646.     )
  647. {
  648.     signal(sig, switch_away);
  649.     video_flags |= VIDEO_SWITCH_AWAY;
  650. }
  651.  
  652. STATIC void
  653. switch_back(
  654.     int        sig
  655.     )
  656. {
  657.     signal(sig, switch_back);
  658.     video_flags |= VIDEO_SWITCH_BACK;
  659. }
  660.  
  661.